package yxy.game.pm2.module.infinite;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;

import org.redisson.api.RMap;
import yxy.cherry.battle.Battle;
import yxy.cherry.battle.module.Position;
import yxy.cherry.battle.module.record.FighterPosition;
import yxy.cherry.battle.module.record.FighterSide;
import yxy.cherry.battle.module.record.result.BattleResult;
import yxy.cherry.battle.module.record.result.StatisticFighter;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.infinite;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.cherry.game.base.redis.RedisType;
import yxy.game.pm2.bean.Currency;
import yxy.game.pm2.bean.Format;
import yxy.game.pm2.bean.Format.FormatType;
import yxy.game.pm2.bean.reset.InfiniteReset;
import yxy.game.pm2.bean.currency.Currencies;
import yxy.game.pm2.bean.currency.CurrencyType;
import yxy.game.pm2.message.BattleMessage;
import yxy.game.pm2.message.InfiniteMessage;
import yxy.game.pm2.module.CurrencyHandle;
import yxy.game.pm2.module.battle.*;
import yxy.game.pm2.module.battle.FighterModule.InitHpLossRatio;
import yxy.game.pm2.module.hero.FormatHandle;

public class InfiniteHandle extends BattleModuleHandle {

    final public static int battleExpireDay = 2;// 战斗数据过期时间（天）

    static public enum BattleState {
        没有在战斗, 局间三消, 局中战斗, 战斗结算;
    }

    @Override
    protected String code() {
        return BattleType.INFINITE.name();
    }

    static public String battleCode(int index) {
        return String.format("%s:%s", BattleType.INFINITE.name(), index);
    }

    /**
     * 轮间间隔
     */
    static public int minuteRestPeriod() {
        return 30;
    }

    /**
     * 每轮局数
     */
    static public int roundPerPeriod() {
        return 5; // TODO 这个5需要参量化
    }

    /**
     * 进三消
     */
    public BattleMessage.BattleResponse battleResponse(String playerCode, int stage) throws Exception {
        InfiniteModule infiniteModule = InfiniteModule.get(playerCode);
        if (!infiniteModule.isBattling() && infiniteModule.getFormat() != null) {
            infiniteModule.setFormat(null);
        }

        infiniteModule.setCurrent(stage - 1);
        infiniteModule.set();

        BattleHandle battleHandle = new BattleHandle();
        BattleModule battleModule = createBattleModule(playerCode, stage, 0);
        battleModule.set(battleExpireDay);
        return battleHandle.battleResponse(battleModule);
    }

    public Collection<InfiniteMessage.InfiniteBattle> battleResponseExecute(String playerCode, BattleMessage.BattleExecuteRequest request) {
        int[] angersTeamA = null;
        if (request != null) {
            List<BattleMessage.FighterInfo> fighterInfos = request.getFormatList();
            angersTeamA = new BattleHandle().angersFromFormatList(fighterInfos, FighterSide.LEFT);
        }

        return battleResponseExecute(playerCode, angersTeamA, DateTime.now(), InfiniteModule.get(playerCode));
    }

    private Collection<InfiniteMessage.InfiniteBattle> battleResponseExecute(String playerCode, int[] angersTeamA, DateTime startTime,
                                                                             InfiniteModule infiniteModule) {
        ArrayList<InfiniteMessage.InfiniteBattle> resps = new ArrayList<>();

        BattleModule battleModule = BattleModule.get(playerCode, battleCode(0));
        if (battleModule == null) {
            return null;
        }
        InfiniteEntry infiniteEntry = new InfiniteEntry(infiniteModule);
        infiniteEntry.getBattleModules().clear();
        infiniteEntry.getBattleModules().add(battleModule);
        infiniteEntry.setBattling(true);

        new InfiniteHandle().battle(playerCode, angersTeamA, startTime, infiniteEntry);

        BattleHandle battleHandle = new BattleHandle();
        CurrencyHandle currencyHandle = new CurrencyHandle();
        for (BattleModule battle : infiniteEntry.getBattleModules()) {
            InfiniteMessage.InfiniteBattle.Builder builder = InfiniteMessage.InfiniteBattle.newBuilder();
            builder.setPlayback(battleHandle.playback(battle));// , team_a, team_b));
            builder.addAllRewards(currencyHandle.packItems(battle.getSettlement().reward()));
            resps.add(builder.build());
        }

        infiniteModule = infiniteEntry.resetModule(infiniteModule);
        infiniteModule.set();

        return resps;
    }

    public void battle(String playerCode, int[] angersTeamA, DateTime startTime, InfiniteEntry infiniteEntry) {
        int rounds = roundPerPeriod();
        int stage = infiniteEntry.getStage() + 1;

        BattleModule battleModule = null;
        if (infiniteEntry.getBattleModules().size() > 0) {
            battleModule = infiniteEntry.getBattleModules().getFirst();
        } else {
            battleModule = createBattleModule(infiniteEntry, stage, 0);
        }
        initSettlementRewards(infiniteEntry, battleModule);

        BattleHandle battleHandle = new BattleHandle();
        for (int i = 1; i <= rounds; i++) {
            System.err.println("战斗 stage:::	" + stage);
            battleHandle.battleResponseExecute(battleModule, BattleHandle.defaultBattleRoundLimit, false, angersTeamA, null);
            if (stage % 100 == 0 && stage / 100 > 2) {
                String recordcode = String.format("%s:%s:Round:%s", battleModule.getType(), playerCode, stage);
                battleModule.saveRecord(recordcode, 7);
            }

            saveHp(playerCode, infiniteEntry, battleModule);// 缓存血量
            battleModule.timeline().setStartTime(startTime);
            battleModule.time();

            if (!battleModule.getBattleResult().equals(BattleResult.LEFT_WIN)) {
                break;
            }
            infiniteEntry.getRewards().clear();
            infiniteEntry.getRewards().addAll(Currency.merge(battleModule.getSettlement().reward()));
//			System.err.println("AA::" + infiniteEntry.getRewards());
            if (i == rounds) {
                break;
            }
            stage++;
            infinite data = DataCenter.getData(stage, infinite.class);
            if (data == null) {
                // 已经完成最后一关
                break;
            }
            infiniteEntry.setStage(stage);
            angersTeamA = cacheAnger(battleModule, FighterSide.LEFT);// 缓存怒气
            startTime = battleModule.timeline().getEndTime();
            battleModule = createBattleModule(infiniteEntry, stage, i);
            initSettlementRewards(infiniteEntry, battleModule);
            infiniteEntry.getBattleModules().add(battleModule);
        }
        infiniteEntry.setStage(stage);
    }

    private void initSettlementRewards(InfiniteEntry infiniteEntry, BattleModule battleModule) {
        SettlementInfinite settlement = (SettlementInfinite) battleModule.getSettlement();
        int stage = settlement.getStage();
        if (stage > infiniteEntry.getToday() && stage > infiniteEntry.getStart()) {
            infinite data = DataCenter.getData(stage - 1, infinite.class);
            if (data == null) {
                return;
            }
            Collection<Currency> rewards = Currency.create(data.getRewardtype(), data.getRewardid(), data.getRewardnum());
            settlement.getRewards().addAll(infiniteEntry.getRewards());
//			System.err.println("BB::" + settlement.getRewards());
            settlement.getRewards().addAll(rewards);
//			System.err.println("BC::" + settlement.getRewards());
//			battleModule.set();
            for (Currency currency : settlement.getRewards()) {
                if (currency.getType().equals(CurrencyType.CT_钱币) && currency.getNumber() > 3755689520L) {
                    System.err.println("神将试炼预设资源有点大::[" + settlement.getPlayerCode() + "]stage:" + stage + ":" + currency.toString());
                }
                if (currency.getType().equals(CurrencyType.CT_武将经验) && currency.getNumber() > 1877852360L) {
                    System.err.println("神将试炼预设资源有点大::[" + settlement.getPlayerCode() + "]stage:" + stage + ":" + currency.toString());
                }
            }
        }
    }

    private BattleModule createBattleModule(String playerCode, int stage, int index) throws Exception {
        InfiniteModule infiniteModule = InfiniteModule.get(playerCode);
        BattleHandle battleHandle = new BattleHandle();

        BattleModule battleModule = BattleModule.create(playerCode);
        battleModule.setType(BattleType.INFINITE);
        battleModule.setCode(battleCode(index));

        // 玩家的team
        Format format = infiniteModule.getFormat();
        if (format == null) {
            infiniteModule.setFormat(new FormatHandle().get(playerCode, FormatType.普通));
            infiniteModule.set();
        }
        TeamModule teamA = battleHandle.teamPlayer(playerCode, infiniteModule.getFormat());
        Map<Position, String> heroCodes = new FormatHandle().formatCodes(playerCode, infiniteModule.getFormat());
        for (Position position : Position.values()) {
            FighterModule fighterModule = teamA.fighter(position);
            String code = heroCodes.get(position);
            if (code == null || fighterModule == null) {
                continue;
            }
            if (!infiniteModule.getHeroHp().containsKey(code)) {
                continue;
            }
            int ratio = infiniteModule.getHeroHp().get(code);
            fighterModule.setInitHp(new InitHpLossRatio(ratio));
        }
        battleModule.setTeamA(teamA);

        // 征战地图
        TeamModule teamB = teamInfinite(stage);
        battleModule.setTeamB(teamB);

        battleModule.setSettlement(SettlementInfinite.create(playerCode, stage));

        battleModule.set(battleExpireDay);
        return battleModule;
    }

    private BattleModule createBattleModule(InfiniteEntry infiniteEntry, int stage, int index) {
        String playerCode = infiniteEntry.getPlayerCode();
        BattleHandle battleHandle = new BattleHandle();

        BattleModule battleModule = BattleModule.create(playerCode);
        battleModule.setType(BattleType.INFINITE);
        battleModule.setCode(battleCode(index));

        // 玩家的team
        Format format = infiniteEntry.getFormat();
        if (format == null) {
            infiniteEntry.setFormat(new FormatHandle().get(playerCode, FormatType.普通));
        }

        TeamModule teamA = battleHandle.teamPlayer(playerCode, format);
        Map<Position, String> heroCodes = new FormatHandle().formatCodes(playerCode, format);
        for (Position position : Position.values()) {
            FighterModule fighterModule = teamA.fighter(position);
            String code = heroCodes.get(position);
            if (code == null || fighterModule == null) {
                continue;
            }
            if (!infiniteEntry.getHeroHp().containsKey(code)) {
                continue;
            }
            int ratio = infiniteEntry.getHeroHp().get(code);
            fighterModule.setInitHp(new InitHpLossRatio(ratio));
        }
        battleModule.setTeamA(teamA);

        // 征战地图
        TeamModule teamB = teamInfinite(stage);
        battleModule.setTeamB(teamB);

        battleModule.setSettlement(SettlementInfinite.create(playerCode, stage));

        return battleModule;
    }

    public TeamModule teamInfinite(int stage) {
        TeamModule team = new TeamModule();
        infinite mapdata = DataCenter.getData(stage, infinite.class);

        RMap<String, ArrayList<FighterModule>> rMap = RedisManager.getInstance().getConnection(RedisType.REDIS_DATA).client().getMap("INIT:infinite");
        JSONArray arrary = (JSONArray) JSONArray.toJSON(rMap.get(String.valueOf(stage)));
        ArrayList<FighterModule> fighterModules = JSON.parseObject(arrary.toString(), new TypeReference<ArrayList<FighterModule>>() {
        });
        Battle.battleLogger(1, "神将试炼第:::: " + stage + " 关");
        // 武将
        for (int i = 0; i < mapdata.getHeroid().length; i++) {
            Position position = Position.forValue(i + 1);
            int heroid = mapdata.getHeroid()[i];
            if (heroid == -1) continue;
            FighterModule fighterModule = fighterModules.get(i);
            team.addfighter(position, fighterModule);
        }
        // 神器
        WeaponModule weapon = WeaponModule.create(mapdata.getWeapondataid(), mapdata.getWeaponlv(), 0, 0, mapdata.getWeaponskilllv());
        team.setWeapon(weapon);

        // 信息
        team.setName(mapdata.getName());
        team.setHead(mapdata.getHeadid());
        team.setPower(team.power());

        return team;
    }


    //神将试炼重置关卡
    public void changeMap(String playerCode) {
        String isChangeInfinite = InfiniteReset.get(playerCode);
        if (StringUtils.isEmpty(isChangeInfinite)) {
            Battle.battleLogger(1, "--------------兼容处理:神将试炼重置关卡---------------");
            InfiniteModule.removeAllFromRedis(playerCode);
            InfiniteModule.deleteFromTable(playerCode);
            InfiniteReset.set(playerCode, "1");
        }
    }


//	private void saveHp(String playerCode, InfiniteModule infiniteModule, BattleModule battleModule) {
////		try {
////			if (infiniteModule.tryLock()) {
//		Map<Position, String> heroCodes = new FormatHandle().formatCodes(playerCode, infiniteModule.getFormat());
//		for (StatisticFighter fighter : battleModule.getStatistics()) {
//			if (!fighter.getPos().getSide().equals(FighterSide.LEFT)) {
//				continue;
//			}
//			Position position = fighter.getPos().getPosition();
//			if (position == null) {
//				continue;
//			}
//			int ratio = (int) (fighter.getHpc() * 10000 / fighter.getHpu());
//			String heroCode = heroCodes.get(fighter.getPos().getPosition());
//			if (heroCode != null && ratio < 10000) {
//				infiniteModule.getHeroHp().put(heroCode, ratio);
//			}
//		}
////		infiniteModule.set();
////			}
////		} catch (Exception e) {
////		} finally {
////			infiniteModule.unlock();
////		}
//	}

    private void saveHp(String playerCode, InfiniteEntry infiniteEntry, BattleModule battleModule) {
        Map<Position, String> heroCodes = new FormatHandle().formatCodes(playerCode, infiniteEntry.getFormat());
        for (StatisticFighter fighter : battleModule.getStatistics()) {
            if (!fighter.getPos().getSide().equals(FighterSide.LEFT)) {
                continue;
            }
            Position position = fighter.getPos().getPosition();
            if (position == null) {
                continue;
            }
            int ratio = (int) (fighter.getHpc() * 10000 / fighter.getHpu());
            String heroCode = heroCodes.get(fighter.getPos().getPosition());
            if (heroCode != null && ratio < 10000) {
                infiniteEntry.getHeroHp().put(heroCode, ratio);
            }
        }
    }

    private int[] cacheAnger(BattleModule battleModule, FighterSide fighterSide) {
        int[] angers = new int[7];
        for (StatisticFighter fighter : battleModule.getStatistics()) {
            if (!fighter.getPos().getSide().equals(fighterSide)) {
                continue;
            }
            FighterPosition fp = fighter.getPos();
            if (fp.equals(FighterPosition.NBL) || fp.equals(FighterPosition.NBR)) {
                angers[0] = fighter.getAng();
                continue;
            }
            if (fp.equals(FighterPosition.SSL) || fp.equals(FighterPosition.SSR)) {
                angers[0] = fighter.getAng();
                continue;
            }

            angers[fp.getPosition().getValue()] = fighter.getAng();
        }
        return angers;
    }

    /**
     * 终战结算
     */
    public void settleStage(String playerCode, int stage) {
        InfiniteModule infiniteModule = InfiniteModule.get(playerCode);

        infiniteModule.pass(stage - 1);

        infiniteModule.setBattling(false);
        infiniteModule.getBattles().clear();
        infiniteModule.setFormat(null);
        infiniteModule.setHeroHp(null);
        infiniteModule.getRewards().clear();
        infiniteModule.setCurrent(0);

        infiniteModule.set();
    }

    static public class InfiniteEntry {
        private String playerCode;

        private int today;// 今日最高通关
        private int start;// 今日起始关卡

        private int stage;// 当前关卡

        private boolean battling;
        private LinkedList<BattleModule> battleModules = new LinkedList<>();
        private Format format;
        private HashMap<String, Integer> heroHp = new HashMap<>();// 武将损失血量万分比
        private Currencies rewards = new Currencies();
        private DateTime tickTime;

        private BattleModule settleBattle;

        public InfiniteEntry(InfiniteModule infiniteModule) {
            this.playerCode = infiniteModule.getPlayerCode();
            this.battling = infiniteModule.isBattling();
            this.tickTime = infiniteModule.getTickTime();
            this.today = infiniteModule.getToday();
            this.start = infiniteModule.getStart();
            this.stage = infiniteModule.getCurrent();
            this.format = infiniteModule.getFormat();
            this.heroHp.putAll(infiniteModule.getHeroHp());
            this.rewards.addAll(infiniteModule.getRewards());
            for (String battleCode : infiniteModule.getBattles()) {
                BattleModule battleModule = BattleModule.get(playerCode, battleCode);
                this.battleModules.add(battleModule);
            }
        }

        public InfiniteModule resetModule(InfiniteModule infiniteModule) {
            infiniteModule.getBattles().clear();
            for (BattleModule battleModule : getBattleModules()) {
                battleModule.set(battleExpireDay);
                infiniteModule.getBattles().add(battleModule.getCode());
            }
            infiniteModule.setHeroHp(getHeroHp());
            infiniteModule.setRewards(getRewards());
            infiniteModule.setBattling(isBattling());
            infiniteModule.setCurrent(getStage());

            return infiniteModule;
        }

        public String getPlayerCode() {
            return playerCode;
        }

        public void setBattling(boolean battling) {
            this.battling = battling;
        }

        public boolean isBattling() {
            return battling;
        }

        public void setStage(int stage) {
            this.stage = stage;
        }

        public int getStage() {
            return stage;
        }

        public int getToday() {
            return today;
        }

        public int getStart() {
            return start;
        }

        public void setBattleModules(LinkedList<BattleModule> battleModules) {
            this.battleModules = battleModules;
        }

        public LinkedList<BattleModule> getBattleModules() {
            return battleModules;
        }

        public void setSettleBattle(BattleModule settleBattle) {
            this.settleBattle = settleBattle;
        }

        public BattleModule getSettleBattle() {
            return settleBattle;
        }

        public void setFormat(Format format) {
            this.format = format;
        }

        public Format getFormat() {
            return format;
        }

        public HashMap<String, Integer> getHeroHp() {
            return heroHp;
        }

        public Currencies getRewards() {
            return rewards;
        }

        public DateTime getTickTime() {
            return tickTime;
        }

        public BattleModule getLastBattle() {
//			BattleModule lastBattle = null;
//			for (BattleModule battleModule : battleModules) {
//				if (lastBattle == null) {
//					lastBattle = battleModule;
//					continue;
//				}
//				if (battleModule.timeline().getEndTime().isAfter(lastBattle.timeline().getEndTime())) {
//					lastBattle = battleModule;
//				}
//			}
//			return lastBattle;
            return getBattleModules().getLast();
        }

    }

}
